import { Lexer, Token } from "../ch2";
import { LookaheadLexer } from "../ch4";

/**
 * 1 lookahead自动扩展 sync(n)
 * 2 markers: mark() release() 回溯解析机制
 */
class Parser {
    input: Lexer

    //缓存解析结果
    markers: number[];
    //lookahead:Token[] 
    //List 长度不固定的数组
    lookahead: Token[];
    p: number = 0;;

    constructor(input: Lexer) {
        this.input = input;
        this.markers = [];
        this.lookahead = [];
        //填充lookahead
        this.sync(1);
    }

    /**
     * 1 lookahead自动扩展
     * @param i 
     */
    sync(i: number) {
        if (this.p + i - 1 > this.lookahead.length - 1) {
            //填充下 自动扩展
            let n = (this.p + i - 1) - (this.lookahead.length - 1);
            this.fill(n);
        }
    }
    /**
     * 填充n个Token到lookahead
     * @param n 
     */
    fill(n: number) {
        for (let i = 1; i <= n; i++) {
            this.lookahead.push(this.input.nextToken())
        }
    }

    /**
     * 向前看第i个Token
     * @param i 
     * @returns 
     */
    LT(i: number) {
        this.sync(i);
        return this.lookahead[this.p + i - 1];
    }

    LA(i: number) {
        return this.LT(i).type
    }

    match(tokenType: number) {
        if (this.LA(1) == tokenType) {
            this.consume();
        } else {

        }
    }
    consume() {
        this.p = this.p + 1;
        if (this.p == this.lookahead.length && !this.isSpeculating()) {
            this.p = 0;
            this.lookahead = [];
        }
        this.sync(1);
    }

    /**
     * 2 回溯的过程 
     * [p1,p2,p3,p4]
     */
    mark() {
        this.markers.push(this.p);
        return this.p;
    }

    release() {
        let marker = this.markers[this.markers.length - 1];
        this.markers.pop();
        this.seek(marker);
    }
    seek(index: number) {
        this.p = index;
    }

    isSpeculating() {
        return this.markers.length > 0
    }

}

class BacktrackParser extends Parser {
    // stat : list EOF | asssign EOF
    // stat : list EOF | list '=' list EOF
    stat() {
        if (this.stat_alt1()) {
            //解析过程
            this.list();
            this.match(Lexer.EOF_TYPE)
        } else if (this.stat_alt2()) {
            this.assign();
            this.match(Lexer.EOF_TYPE)
        } else {
            throw new Error("stat error");
        }
    }

    //list EOF
    stat_alt1() {
        let success = true;
        //存储当前this.p
        // markser = [0]
        this.mark();
        try {
            //判定过程
            this.list();
            this.match(Lexer.EOF_TYPE)
        } catch (e) {
            success = false;
        }
        // this.p = markers[last] = 0;
        this.release();
        return success
    }
    //assign EOF
    stat_alt2() {
        let success = true;
        this.mark();
        try {
            this.assign();
            this.match(Lexer.EOF_TYPE)
        } catch (e) {
            success = false
        }

        this.release()
        return success
    }
    // assign : list '=' list;
    assign() {
        this.list();
        this.match(LookaheadLexer.EQUALS);
        this.list();
    }
    // list : '[' elements ']'
    list() {
        console.log("ch5 list parser");
        this.match(LookaheadLexer.LBRACK);
        this.elements();
        this.match(LookaheadLexer.RBRACK);
    }

    // elements : element (',' element)*
    elements() {
        this.element();
        while (this.LA(1) == LookaheadLexer.COMMA) {
            this.match(LookaheadLexer.COMMA);
            this.element();
        }
    }
    // element : NAME | NAME '=' NAME | list
    element() {
        if (this.LA(1) == LookaheadLexer.NAME && this.LA(2) == LookaheadLexer.EQUALS) {
            this.match(LookaheadLexer.NAME);
            this.match(LookaheadLexer.EQUALS);
            this.match(LookaheadLexer.NAME)
        } else if (this.LA(1) == LookaheadLexer.NAME) {
            this.match(LookaheadLexer.NAME);
        } else if (this.LA(1) == LookaheadLexer.LBRACK) {
            this.list();
        } else {
            throw new Error("expectin name or list found " + this.LT(1))
        }
    }
}


export {
    Parser,
    BacktrackParser
}